package connection

import (
	"context"
	"errors"
	"fmt"
	"net"
	"sync"
	"zinxtcp/message"
	"zinxtcp/tunny"
	"zinxtcp/utils"
	"zinxtcp/ziface"
)

type Connection struct {
	ctx context.Context
	//当前连接的socket TCP套接字
	Conn *net.TCPConn
	//当前连接的ID 也可以称作为SessionID，ID全局唯一
	ConnID uint32
	//当前连接的关闭状态
	isClosed bool
	//有关冲管道，用于读、写两个goroutine之间的消息通信
	msgBuffChan chan []byte
	//链接属性
	property map[string]interface{}
	//保护链接属性修改的锁
	sync.RWMutex
	//连接管理器
	ConnManager ziface.IConnManager
	ctxSelf     context.Context
	cancelFunc  context.CancelFunc
}

//创建连接的方法
func NewConnection(ctx context.Context, conn *net.TCPConn, connID uint32, connMgr ziface.IConnManager) ziface.IConnection {
	ctxS, cf := context.WithCancel(context.Background())
	c := &Connection{
		ctx:         ctx,
		Conn:        conn,
		ConnID:      connID,
		isClosed:    false,
		msgBuffChan: make(chan []byte, utils.GlobalObject.MaxMsgChanLen),
		property:    make(map[string]interface{}), //对链接属性map初始化
		ConnManager: connMgr,
		ctxSelf:     ctxS,
		cancelFunc:  cf,
	}
	return c
}

/* 处理conn读数据的Goroutine */
func (c *Connection) StartReader() {
	fmt.Println(c.RemoteAddr().String(), "Reader Goroutine is running")
	defer fmt.Println(c.RemoteAddr().String(), " Reader Goroutine exit!")
	//得到解码器
	unpackFunc := c.ConnManager.GetEncoder().GetUnpackFunc()

	for {
		select {
		case <-c.ctx.Done():
			fmt.Println(c.RemoteAddr().String(), "Reader Goroutine get signal from ctx manager. ")
			return
		case <-c.ctxSelf.Done():
			fmt.Println(c.RemoteAddr().String(), "Reader Goroutine get signal from ctx self. ")
			return
		default:
			//使用解码器从tcp链接中读取对应的数据包
			msg, err := unpackFunc(c.GetTCPConnection())
			if err != nil {
				fmt.Println(c.RemoteAddr().String(), "Reader Goroutine unpackFunc error: ", err.Error())
				c.Stop()
				return
			}
			sockPack := message.NewSockPack(c, msg)
			tunny.LabourPool.Process(sockPack)
		}
	}
}

/*
   写消息Goroutine， 用户将数据发送给客户端
*/
func (c *Connection) StartWriter() {
	fmt.Println(c.RemoteAddr().String(), "Writer Goroutine is running")
	defer fmt.Println(c.RemoteAddr().String(), " Writer Goroutine exit!")
	defer c.Stop()

	for {
		select {
		case <-c.ctxSelf.Done():
			fmt.Println(c.RemoteAddr().String(), "Writer Goroutine get signal from ctx self. ")
			return
		//针对有缓冲channel需要些的数据处理
		case data, ok := <-c.msgBuffChan:
			if ok {
				//有数据要写给客户端
				if _, err := c.Conn.Write(data); err != nil {
					fmt.Println(c.RemoteAddr().String(), "Writer Goroutine Send Buff Data error:, ", err, " Conn Writer exit")
					return
				}
			} else {
				fmt.Println(c.RemoteAddr().String(), "msgBuffChan is Closed")
				return
			}
		}
	}
}

//启动连接，让当前连接开始工作
func (c *Connection) Start() {
	//2 开启用于写回客户端数据流程的Goroutine
	go c.StartWriter()

	//触发连接开始事件
	connBeginFunc := c.ConnManager.GetConnEvent().GetConnBegin()
	connBeginFunc(c)

	//1 开启处理该链接读取到客户端数据之后的请求业务
	go c.StartReader()
}

func (c *Connection) Join() {}

//停止连接，结束当前连接状态M
func (c *Connection) Stop() {
	fmt.Println(c.RemoteAddr().String(), "Conn Stop()...ConnID = ", c.ConnID)
	//1. 如果当前链接已经关闭
	if c.isClosed == true {
		fmt.Printf("ConnID %d closed already.\n", c.ConnID)
		return
	}
	c.isClosed = true
	//msgBuffChan := c.msgBuffChan
	c.msgBuffChan = nil
	go c.ConnManager.RemoveById(c.ConnID)
	c.cancelFunc()
	//如果用户注册了该链接的关闭回调业务，那么在此刻应该显示调用
	connStopFunc := c.ConnManager.GetConnEvent().GetConnStop()
	connStopFunc(c)
	//close(msgBuffChan)
	// 关闭socket链接
	c.Conn.Close()
	//close(msgBuffChan)
}

//从当前连接获取原始的socket TCPConn
func (c *Connection) GetTCPConnection() *net.TCPConn {
	return c.Conn
}

//获取当前连接ID
func (c *Connection) GetConnID() uint32 {
	return c.ConnID
}

//获取远程客户端地址信息
func (c *Connection) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}

//将包头和负载打包后发送数据给远程的TCP客户端
func (c *Connection) SendMsg(header ziface.IHeader, data []byte) error {
	c.RLock()
	if c.isClosed == true {
		c.RUnlock()
		return errors.New("Connection closed while send msg.")
	}
	c.RUnlock()
	//得到解码器
	packFunc := c.ConnManager.GetEncoder().GetPackFunc()
	dataBytes, err := packFunc(header, data)
	if err != nil {
		fmt.Println("Pack error msg type = ", header.GetMsgType())
		return errors.New("Pack error msg ")
	}
	c.msgBuffChan <- dataBytes
	return err
}

//直接将二进制数据发送数据给远程的TCP客户端
func (c *Connection) SendData(data []byte) error {
	if c.isClosed == true {
		return errors.New("SendData: Connection closed while send msg.")
	}
	if c.msgBuffChan == nil {
		return errors.New("SendData: msgBuffChan is nil while send msg.")
	}
	c.msgBuffChan <- data
	return nil
}

//设置链接属性
func (c *Connection) SetProperty(key string, value interface{}) {
	c.Lock()
	defer c.Unlock()

	c.property[key] = value
}

//获取链接属性
func (c *Connection) GetProperty(key string) (interface{}, error) {
	c.RLock()
	defer c.RUnlock()

	if value, ok := c.property[key]; ok {
		return value, nil
	} else {
		return nil, errors.New("no property found")
	}
}

//移除链接属性
func (c *Connection) RemoveProperty(key string) {
	c.Lock()
	defer c.Unlock()

	delete(c.property, key)
}
